home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH12 / SRC / OBJPGON4.CLS < prev    next >
Encoding:
Text File  |  1996-05-04  |  22.7 KB  |  837 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjPolygon"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' Point3D is defined in module M3OPS.BAS as:
  11. '    Type Point3D
  12. '        coord(1 To 4) As Single
  13. '        trans(1 To 4) As Single
  14. '    End Type
  15.  
  16. Private NumPts As Integer ' Number of points.
  17. Private Points() As Point3D  ' Data points.
  18.  
  19. Private IsCulled As Boolean
  20. ' ************************************************
  21. ' Draw the transformed points on a Form, Printer,
  22. ' or PictureBox. Use the API function Polygon so
  23. ' the polygon will be properly filled to cover
  24. ' polygons behind it.
  25. '
  26. ' Assume the point light source is infinitely far
  27. ' away so the color is the same for the whole
  28. ' polygon.
  29. ' ************************************************
  30. Public Sub DrawShaded(canvas As Object, Optional r As Variant)
  31. Dim pts() As POINTAPI
  32. Dim pt As Integer
  33. Dim status As Integer
  34. Dim nx As Single
  35. Dim ny As Single
  36. Dim nz As Single
  37. Dim lx As Single
  38. Dim ly As Single
  39. Dim lz As Single
  40. Dim vx As Single
  41. Dim vy As Single
  42. Dim vz As Single
  43. Dim rx As Single
  44. Dim ry As Single
  45. Dim rz As Single
  46. Dim l_len As Single
  47. Dim v_len As Single
  48. Dim r_len As Single
  49. Dim intensity As Single
  50. Dim clr As Long
  51. Dim NdotL As Single
  52. Dim RdotV As Single
  53. Dim diffuse_part As Single
  54. Dim ambient_part As Single
  55. Dim specular_part As Single
  56.  
  57.     ' Don't draw if culled.
  58.     If IsCulled Then Exit Sub
  59.        
  60.     ' Fill in the point array.
  61.     ReDim pts(1 To NumPts)
  62.     For pt = 1 To NumPts
  63.         pts(pt).x = Points(pt).trans(1)
  64.         pts(pt).y = Points(pt).trans(2)
  65.     Next pt
  66.  
  67.     ' Find the unit vector pointing toward the light.
  68.     lx = LightX - Points(1).coord(1)
  69.     ly = LightY - Points(1).coord(2)
  70.     lz = LightZ - Points(1).coord(3)
  71.     l_len = Sqr(lx * lx + ly * ly + lz * lz)
  72.     lx = lx / l_len
  73.     ly = ly / l_len
  74.     lz = lz / l_len
  75.     ' We will use l_len later as the distance from
  76.     ' the light to the surface.
  77.     
  78.     ' Find the surface unit normal.
  79.     UnitNormalVector nx, ny, nz
  80.     
  81.     ' Calculate the part due to diffuse reflection.
  82.     NdotL = nx * lx + ny * ly + nz * lz
  83.     If NdotL < 0 Then
  84.         ' The light does not hit the surface.
  85.         diffuse_part = 0
  86.         specular_part = 0
  87.     Else
  88.         diffuse_part = LightKd * NdotL
  89.         
  90.         ' Find the vector V from the surface to the
  91.         ' viewpoint.
  92.         vx = EyeX - Points(1).coord(1)
  93.         vy = EyeY - Points(1).coord(2)
  94.         vz = EyeZ - Points(1).coord(3)
  95.         v_len = Sqr(vx * vx + vy * vy + vz * vz)
  96.         vx = vx / v_len
  97.         vy = vy / v_len
  98.         vz = vz / v_len
  99.         
  100.         ' Find vector R in the mirror direction.
  101.         rx = 2 * nx * NdotL - lx
  102.         ry = 2 * ny * NdotL - ly
  103.         rz = 2 * nz * NdotL - lz
  104.         
  105.         ' Calculate the part due to specular reflection.
  106.         RdotV = rx * vx + ry * vy + rz * vz
  107.         If RdotV < 0 Then
  108.             specular_part = 0
  109.         Else
  110.             specular_part = LightKs * RdotV ^ LightN
  111.         End If
  112.     End If
  113.     
  114.     ' Calculate the part due to ambient light.
  115.     ambient_part = LightIa * LightKa
  116.     
  117.     ' See how intense to make the color.
  118.     intensity = ambient_part + _
  119.         LightIi / (l_len + LightKdist) * _
  120.             (diffuse_part + specular_part)
  121.  
  122.     ' Compute the color.
  123.     clr = &H2000000 + RGB(intensity, intensity, intensity)
  124.     canvas.FillColor = clr
  125.  
  126.     ' Draw the polygon.
  127.     On Error Resume Next
  128.     status = Polygon(canvas.hdc, pts(1), NumPts)
  129. End Sub
  130.  
  131. ' ************************************************
  132. ' Draw the transformed points on a Form, Printer,
  133. ' or PictureBox. Use the API function Polygon so
  134. ' the polygon will be properly filled to cover
  135. ' polygons behind it.
  136. ' ************************************************
  137. Public Sub DrawOrdered(canvas As Object, Optional r As Variant)
  138. Dim pts() As POINTAPI
  139. Dim pt As Integer
  140. Dim status As Integer
  141.  
  142.     ' Don't draw if culled.
  143.     If IsCulled Then Exit Sub
  144.        
  145.     ' Fill in the point array.
  146.     ReDim pts(1 To NumPts)
  147.     For pt = 1 To NumPts
  148.         pts(pt).x = Points(pt).trans(1)
  149.         pts(pt).y = Points(pt).trans(2)
  150.     Next pt
  151.  
  152.     ' Draw the polygon.
  153.     On Error Resume Next
  154.     status = Polygon(canvas.hdc, pts(1), NumPts)
  155. End Sub
  156.  
  157.  
  158.  
  159. ' ************************************************
  160. ' Return the minimum and maximum coordinates.
  161. ' ************************************************
  162. Public Sub GetExtent(xmin As Single, xmax As Single, ymin As Single, ymax As Single, zmin As Single, zmax As Single)
  163. Dim i As Integer
  164. Dim x As Single
  165. Dim y As Single
  166. Dim Z As Single
  167.  
  168.     xmin = Points(1).trans(1)
  169.     xmax = xmin
  170.     ymin = Points(1).trans(2)
  171.     ymax = ymin
  172.     zmin = Points(1).trans(3)
  173.     zmax = zmin
  174.     For i = 2 To NumPts
  175.         x = Points(i).trans(1)
  176.         y = Points(i).trans(2)
  177.         Z = Points(i).trans(3)
  178.         If xmin > x Then xmin = x
  179.         If xmax < x Then xmax = x
  180.         If ymin > y Then ymin = y
  181.         If ymax < y Then ymax = y
  182.         If zmin > Z Then zmin = Z
  183.         If zmax < Z Then zmax = Z
  184.     Next i
  185. End Sub
  186.  
  187.  
  188.  
  189.  
  190. ' ************************************************
  191. ' Return the coordinates of a point on the polygon.
  192. ' ************************************************
  193. Public Sub GetTransformedPoint(index As Integer, x As Single, y As Single, Z As Single)
  194.     x = Points(index).trans(1)
  195.     y = Points(index).trans(2)
  196.     Z = Points(index).trans(3)
  197. End Sub
  198.  
  199.  
  200. ' ************************************************
  201. ' See where the projections of two segments cross.
  202. ' Return true if the segments cross, false
  203. ' otherwise.
  204. ' ************************************************
  205. Function FindCrossing( _
  206.     ax1 As Single, ay1 As Single, az1 As Single, _
  207.     ax2 As Single, ay2 As Single, az2 As Single, _
  208.     bx1 As Single, by1 As Single, bz1 As Single, _
  209.     bx2 As Single, by2 As Single, bz2 As Single, _
  210.     x As Single, y As Single, z1 As Single, z2 As Single) _
  211.         As Boolean
  212. Dim dxa As Single
  213. Dim dya As Single
  214. Dim dza As Single
  215. Dim dxb As Single
  216. Dim dyb As Single
  217. Dim dzb As Single
  218. Dim t1 As Single
  219. Dim t2 As Single
  220. Dim denom As Single
  221.  
  222.     dxa = ax2 - ax1
  223.     dya = ay2 - ay1
  224.     dxb = bx2 - bx1
  225.     dyb = by2 - by1
  226.     
  227.     FindCrossing = False
  228.     
  229.     denom = dxb * dya - dyb * dxa
  230.     ' If the segments are parallel, stop.
  231.     If denom < 0.01 And denom > -0.01 Then Exit Function
  232.  
  233.     t2 = (ax1 * dya - ay1 * dxa - bx1 * dya + by1 * dxa) / denom
  234.     If t2 < 0 Or t2 > 1 Then Exit Function
  235.     
  236.     t1 = (ax1 * dyb - ay1 * dxb - bx1 * dyb + by1 * dxb) / denom
  237.     If t1 < 0 Or t1 > 1 Then Exit Function
  238.  
  239.     ' Compute the points of overlap.
  240.     x = ax1 + t1 * dxa
  241.     y = ay1 + t1 * dya
  242.     dza = az2 - az1
  243.     dzb = bz2 - bz1
  244.     z1 = az1 + t1 * dza
  245.     z2 = bz1 + t2 * dzb
  246.     FindCrossing = True
  247. End Function
  248.  
  249. ' ************************************************
  250. ' Return the number of points.
  251. ' ************************************************
  252. Property Get NumPoints() As Integer
  253.     NumPoints = NumPts
  254. End Property
  255.  
  256. ' ************************************************
  257. ' Return true if this polygon partially obscures
  258. ' (has greater Z value than) polygon obj.
  259. '
  260. ' We assume one polygon may obscure the other, but
  261. ' they cannot obscure each other.
  262. '
  263. ' This check is executed by seeing where the
  264. ' projections of the edges of the polygons cross.
  265. ' Where they cross, see if one Z value is greater
  266. ' than the other.
  267. '
  268. ' If no edges cross, see if one polygon contains
  269. ' the other. If so, there is an overlap.
  270. ' ************************************************
  271. Public Function Obscures(obj As ObjPolygon) As Boolean
  272. Dim num As Integer
  273. Dim i As Integer
  274. Dim j As Integer
  275. Dim xi1 As Single
  276. Dim yi1 As Single
  277. Dim zi1 As Single
  278. Dim xi2 As Single
  279. Dim yi2 As Single
  280. Dim zi2 As Single
  281. Dim xj1 As Single
  282. Dim yj1 As Single
  283. Dim zj1 As Single
  284. Dim xj2 As Single
  285. Dim yj2 As Single
  286. Dim zj2 As Single
  287. Dim x As Single
  288. Dim y As Single
  289. Dim z1 As Single
  290. Dim z2 As Single
  291.  
  292.     num = obj.NumPoints
  293.     
  294.     ' Check each edge in this polygon.
  295.     GetTransformedPoint NumPts, xi1, yi1, zi1
  296.     For i = 1 To NumPts
  297.         GetTransformedPoint i, xi2, yi2, zi2
  298.     
  299.         ' Compare with each edge in the other.
  300.         obj.GetTransformedPoint num, xj1, yj1, zj1
  301.         For j = 1 To num
  302.             obj.GetTransformedPoint j, xj2, yj2, zj2
  303.             ' See if the segments cross.
  304.             If FindCrossing( _
  305.                 xi1, yi1, zi1, _
  306.                 xi2, yi2, zi2, _
  307.                 xj1, yj1, zj1, _
  308.                 xj2, yj2, zj2, _
  309.                 x, y, z1, z2) _
  310.             Then
  311.                 If z1 - z2 > 0.01 Then
  312.                     ' z1 > z2. We obscure it.
  313.                     Obscures = True
  314.                     Exit Function
  315.                 End If
  316.                 If z2 - z1 > 0.01 Then
  317.                     ' z2 > z1. It obscures us.
  318.                     Obscures = False
  319.                     Exit Function
  320.                 End If
  321.             End If
  322.             
  323.             xj1 = xj2
  324.             yj1 = yj2
  325.             zj1 = zj2
  326.         Next j
  327.         
  328.         xi1 = xi2
  329.         yi1 = yi2
  330.         zi1 = zi2
  331.     Next i
  332.     
  333.     ' No edges cross. See if one polygon contains
  334.     ' the other.
  335.     
  336.     ' If any points of one polygon are inside the
  337.     ' other, then they must all be. Since the
  338.     ' IsAbove tests were inconclusive, some points
  339.     ' in one polygon are on the "bad" side of the
  340.     ' other. In that case there is an overlap.
  341.     
  342.     ' See if this polygon is inside the other.
  343.     GetTransformedPoint 1, xi1, yi1, zi1
  344.     If obj.PointInside(xi1, yi1) Then
  345.         Obscures = True
  346.         Exit Function
  347.     End If
  348.     
  349.     ' See if the other polygon is inside this one.
  350.     obj.GetTransformedPoint 1, xi1, yi1, zi1
  351.     If PointInside(xi1, yi1) Then
  352.         Obscures = True
  353.         Exit Function
  354.     End If
  355.     
  356.     Obscures = False
  357. End Function
  358.  
  359. ' ************************************************
  360. ' Return true if the point projection lies within
  361. ' this polygon's projection.
  362. ' ************************************************
  363. Function PointInside(x As Single, y As Single) As Boolean
  364. Dim i As Integer
  365. Dim theta1 As Double
  366. Dim theta2 As Double
  367. Dim dtheta As Double
  368. Dim dx As Double
  369. Dim dy As Double
  370. Dim angles As Double
  371.  
  372.     dx = Points(NumPts).trans(1) - x
  373.     dy = Points(NumPts).trans(2) - y
  374.     theta1 = Arctan2(CSng(dx), CSng(dy))
  375.     If theta1 < 0 Then theta1 = theta1 + 2 * PI
  376.     For i = 1 To NumPts
  377.         dx = Points(i).trans(1) - x
  378.         dy = Points(i).trans(2) - y
  379.         theta2 = Arctan2(CSng(dx), CSng(dy))
  380.         If theta2 < 0 Then theta2 = theta2 + 2 * PI
  381.         dtheta = theta2 - theta1
  382.         If dtheta > PI Then dtheta = dtheta - 2 * PI
  383.         If dtheta < -PI Then dtheta = dtheta + 2 * PI
  384.         angles = angles + dtheta
  385.         theta1 = theta2
  386.     Next i
  387.     
  388.     PointInside = (Abs(angles) > 0.001)
  389. End Function
  390.  
  391.  
  392. ' ************************************************
  393. ' Return true if this polygon is completly below
  394. ' the plane containing obj.
  395. ' ************************************************
  396. Public Function IsBelow(obj As ObjPolygon) As Boolean
  397. Dim nx As Single
  398. Dim ny As Single
  399. Dim nz As Single
  400. Dim px As Single
  401. Dim py As Single
  402. Dim pz As Single
  403. Dim dx As Single
  404. Dim dy As Single
  405. Dim dz As Single
  406. Dim cx As Single
  407. Dim cy As Single
  408. Dim cz As Single
  409. Dim i As Integer
  410.  
  411.     ' Compute a downward pointing normal to the plane.
  412.     obj.TransformedNormalVector nx, ny, nz
  413.     If nz > 0 Then
  414.         nx = -nx
  415.         ny = -ny
  416.         nz = -nz
  417.     End If
  418.     
  419.     ' Get a point on the plane.
  420.     obj.GetTransformedPoint 1, px, py, pz
  421.     
  422.     ' See if the points in this polygon all lie
  423.     For i = 1 To NumPts
  424.         ' Get the vector from plane to point.
  425.         dx = Points(i).trans(1) - px
  426.         dy = Points(i).trans(2) - py
  427.         dz = Points(i).trans(3) - pz
  428.             
  429.         ' If the dot product < 0, the point is
  430.         ' below the plane.
  431.         If dx * nx + dy * ny + dz * nz < -0.01 Then
  432.             IsBelow = False
  433.             Exit Function
  434.         End If
  435.     Next i
  436.     IsBelow = True
  437. End Function
  438.  
  439.  
  440. ' ************************************************
  441. ' Return true if this polygon is completly above
  442. ' the plane containing obj.
  443. ' ************************************************
  444. Public Function IsAbove(obj As ObjPolygon) As Boolean
  445. Dim nx As Single
  446. Dim ny As Single
  447. Dim nz As Single
  448. Dim px As Single
  449. Dim py As Single
  450. Dim pz As Single
  451. Dim dx As Single
  452. Dim dy As Single
  453. Dim dz As Single
  454. Dim cx As Single
  455. Dim cy As Single
  456. Dim cz As Single
  457. Dim i As Integer
  458.  
  459.     ' Compute an upward pointing normal to the plane.
  460.     obj.TransformedNormalVector nx, ny, nz
  461.     If nz < 0 Then
  462.         nx = -nx
  463.         ny = -ny
  464.         nz = -nz
  465.     End If
  466.     
  467.     ' Get a point on the plane.
  468.     obj.GetTransformedPoint 1, px, py, pz
  469.     
  470.     ' See if the points in this polygon all lie
  471.     For i = 1 To NumPts
  472.         ' Get the vector from plane to point.
  473.         dx = Points(i).trans(1) - px
  474.         dy = Points(i).trans(2) - py
  475.         dz = Points(i).trans(3) - pz
  476.             
  477.         ' If the dot product < 0, the point is
  478.         ' below the plane.
  479.         If dx * nx + dy * ny + dz * nz < -0.01 Then
  480.             IsAbove = False
  481.             Exit Function
  482.         End If
  483.     Next i
  484.     IsAbove = True
  485. End Function
  486.  
  487.  
  488. ' ***********************************************
  489. ' Return the maximum transformed Z value for this
  490. ' object.
  491. ' ***********************************************
  492. Property Get Distance(x As Single, y As Single, Z As Single) As Single
  493. Dim best As Single
  494. Dim dist As Single
  495. Dim dx As Single
  496. Dim dy As Single
  497. Dim dz As Single
  498. Dim i As Integer
  499.  
  500.     best = INFINITY
  501.     For i = 1 To NumPts
  502.         dx = Points(i).coord(1) - x
  503.         dy = Points(i).coord(2) - y
  504.         dz = Points(i).coord(3) - Z
  505.         dist = dx * dx + dy * dy + dz * dz
  506.         If best > dist Then best = dist
  507.     Next i
  508.     Distance = Sqr(best)
  509. End Property
  510.  
  511. ' ***********************************************
  512. ' Return the maximum transformed Z value for this
  513. ' object.
  514. ' ***********************************************
  515. Property Get zmax() As Single
  516. Dim best As Single
  517. Dim Z As Single
  518. Dim i As Integer
  519.  
  520.     best = Points(1).trans(3)
  521.     For i = 2 To NumPts
  522.         Z = Points(i).trans(3)
  523.         If best < Z Then best = Z
  524.     Next i
  525.     zmax = best
  526. End Property
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533. ' ***********************************************
  534. ' Compute a transformed normal vector.
  535. ' ***********************************************
  536. Public Sub TransformedNormalVector(nx As Single, ny As Single, nz As Single)
  537. Dim Ax As Single
  538. Dim Ay As Single
  539. Dim Az As Single
  540. Dim Bx As Single
  541. Dim By As Single
  542. Dim Bz As Single
  543.  
  544.     Ax = Points(2).trans(1) - Points(1).trans(1)
  545.     Ay = Points(2).trans(2) - Points(1).trans(2)
  546.     Az = Points(2).trans(3) - Points(1).trans(3)
  547.     Bx = Points(3).trans(1) - Points(2).trans(1)
  548.     By = Points(3).trans(2) - Points(2).trans(2)
  549.     Bz = Points(3).trans(3) - Points(2).trans(3)
  550.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  551. End Sub
  552.  
  553.  
  554.  
  555. ' ***********************************************
  556. ' Compute a normal vector for this polygon.
  557. ' ***********************************************
  558. Public Sub NormalVector(nx As Single, ny As Single, nz As Single)
  559. Dim Ax As Single
  560. Dim Ay As Single
  561. Dim Az As Single
  562. Dim Bx As Single
  563. Dim By As Single
  564. Dim Bz As Single
  565.  
  566.     Ax = Points(2).coord(1) - Points(1).coord(1)
  567.     Ay = Points(2).coord(2) - Points(1).coord(2)
  568.     Az = Points(2).coord(3) - Points(1).coord(3)
  569.     Bx = Points(3).coord(1) - Points(2).coord(1)
  570.     By = Points(3).coord(2) - Points(2).coord(2)
  571.     Bz = Points(3).coord(3) - Points(2).coord(3)
  572.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  573. End Sub
  574.  
  575.  
  576.  
  577.  
  578. ' ***********************************************
  579. ' Compute the unit normal line segment for this
  580. ' polygon.
  581. ' ***********************************************
  582. Sub UnitNormalSegment(x1 As Single, y1 As Single, z1 As Single, x2 As Single, y2 As Single, z2 As Single)
  583. Dim i As Integer
  584. Dim nx As Single
  585. Dim ny As Single
  586. Dim nz As Single
  587.     
  588.     UnitNormalVector nx, ny, nz
  589.     
  590.     x1 = 0
  591.     y1 = 0
  592.     z1 = 0
  593.     For i = 1 To NumPts
  594.         x1 = x1 + Points(i).coord(1)
  595.         y1 = y1 + Points(i).coord(2)
  596.         z1 = z1 + Points(i).coord(3)
  597.     Next i
  598.     x1 = x1 / NumPts
  599.     y1 = y1 / NumPts
  600.     z1 = z1 / NumPts
  601.  
  602.     x2 = x1 + nx
  603.     y2 = y1 + ny
  604.     z2 = z1 + nz
  605. End Sub
  606.  
  607.  
  608. ' ***********************************************
  609. ' Compute the unit normal vector for this
  610. ' polygon.
  611. ' ***********************************************
  612. Sub UnitNormalVector(nx As Single, ny As Single, nz As Single)
  613. Dim D As Single
  614.  
  615.     NormalVector nx, ny, nz
  616.     D = Sqr(nx * nx + ny * ny + nz * nz)
  617.     nx = nx / D
  618.     ny = ny / D
  619.     nz = nz / D
  620. End Sub
  621.  
  622.  
  623.  
  624.  
  625.  
  626. ' ***********************************************
  627. ' Set or clear the IsCulled flag.
  628. ' ***********************************************
  629. Property Let Culled(value As Boolean)
  630.     IsCulled = value
  631. End Property
  632.  
  633.  
  634. ' ***********************************************
  635. ' Return true if the polygon has been culled.
  636. ' ***********************************************
  637. Property Get Culled() As Boolean
  638.     Culled = IsCulled
  639. End Property
  640.  
  641. ' ***********************************************
  642. ' Return a string indicating the object type.
  643. ' ***********************************************
  644. Property Get ObjectType() As String
  645.     ObjectType = "POLYGON"
  646. End Property
  647.  
  648. ' ************************************************
  649. ' Add one or more points to the polygon.
  650. ' ************************************************
  651. Public Sub AddPoint(ParamArray coord() As Variant)
  652. Dim num_pts As Integer
  653. Dim i As Integer
  654. Dim pt As Integer
  655.  
  656.     num_pts = (UBound(coord) + 1) \ 3
  657.     ReDim Preserve Points(1 To NumPts + num_pts)
  658.  
  659.     pt = 0
  660.     For i = 1 To num_pts
  661.         Points(NumPts + i).coord(1) = coord(pt)
  662.         Points(NumPts + i).coord(2) = coord(pt + 1)
  663.         Points(NumPts + i).coord(3) = coord(pt + 2)
  664.         Points(NumPts + i).coord(4) = 1#
  665.         pt = pt + 3
  666.     Next i
  667.  
  668.     NumPts = NumPts + num_pts
  669. End Sub
  670.  
  671.  
  672. ' ************************************************
  673. ' Draw the object into a metafile.
  674. ' ************************************************
  675. Public Sub MakeWMF(mhdc As Integer)
  676. Dim pts() As POINTAPI
  677. Dim pt As Integer
  678. Dim status As Integer
  679.  
  680.     ' Don't draw if culled.
  681.     If IsCulled Then Exit Sub
  682.        
  683.     ' Fill in the point array.
  684.     ReDim pts(1 To NumPts)
  685.     For pt = 1 To NumPts
  686.         pts(pt).x = Points(pt).trans(1)
  687.         pts(pt).y = Points(pt).trans(2)
  688.     Next pt
  689.  
  690.     ' Draw the polygon.
  691.     On Error Resume Next
  692.     status = Polygon(mhdc, pts(1), NumPts)
  693. End Sub
  694.  
  695. ' ***********************************************
  696. ' Fix the data coordinates at their transformed
  697. ' values.
  698. ' ***********************************************
  699. Public Sub FixPoints()
  700. Dim i As Integer
  701. Dim j As Integer
  702.  
  703.     For i = 1 To NumPts
  704.         For j = 1 To 3
  705.             Points(i).coord(j) = Points(i).trans(j)
  706.         Next j
  707.     Next i
  708. End Sub
  709.  
  710. ' ************************************************
  711. ' Apply a transformation matrix which may not
  712. ' contain 0, 0, 0, 1 in the last column to the
  713. ' object.
  714. ' ************************************************
  715. Public Sub ApplyFull(M() As Single)
  716. Dim i As Integer
  717.  
  718.     If IsCulled Then Exit Sub
  719.     For i = 1 To NumPts
  720.         m3ApplyFull Points(i).coord, M, Points(i).trans
  721.     Next i
  722. End Sub
  723.  
  724. ' ************************************************
  725. ' Apply a transformation matrix to the object.
  726. ' ************************************************
  727. Public Sub Apply(M() As Single)
  728. Dim i As Integer
  729.  
  730.     If IsCulled Then Exit Sub
  731.     For i = 1 To NumPts
  732.         m3Apply Points(i).coord, M, Points(i).trans
  733.     Next i
  734. End Sub
  735.  
  736.  
  737. ' ************************************************
  738. ' Apply a nonlinear transformation.
  739. ' ************************************************
  740. Public Sub Distort(D As Object)
  741. Dim i As Integer
  742.  
  743.     For i = 1 To NumPts
  744.         D.Distort Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  745.     Next i
  746. End Sub
  747.  
  748. ' ************************************************
  749. ' Write a polyline to a file using Write.
  750. ' Begin with "POLYGON" to identify this object.
  751. ' ************************************************
  752. Public Sub FileWrite(filenum As Integer)
  753. Dim i As Integer
  754.  
  755.     Write #filenum, "POLYGON", NumPts
  756.     
  757.     ' Write the points.
  758.     For i = 1 To NumPts
  759.         Write #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  760.     Next i
  761. End Sub
  762.  
  763. ' ************************************************
  764. ' Draw the transformed points on a Form, Printer,
  765. ' or PictureBox.
  766. ' ************************************************
  767. Public Sub Draw(canvas As Object, Optional r As Variant)
  768. Dim pt As Integer
  769.  
  770.     ' Don't draw if culled.
  771.     If IsCulled Then Exit Sub
  772.     
  773.     On Error Resume Next
  774.     canvas.CurrentX = Points(NumPts).trans(1)
  775.     canvas.CurrentY = Points(NumPts).trans(2)
  776.     For pt = 1 To NumPts
  777.         canvas.Line _
  778.             -(Points(pt).trans(1), Points(pt).trans(2))
  779.     Next pt
  780. End Sub
  781. ' ***********************************************
  782. ' Cull if any points are behind the center of
  783. ' projection.
  784. ' ***********************************************
  785. Public Sub ClipEye(r As Single)
  786. Dim pt As Integer
  787.  
  788.     If IsCulled Then Exit Sub
  789.     For pt = 1 To NumPts
  790.         If Points(pt).trans(3) >= r Then Exit For
  791.     Next pt
  792.     If pt <= NumPts Then IsCulled = True
  793. End Sub
  794. ' ***********************************************
  795. ' Perform backface removal.
  796. ' ***********************************************
  797. Public Sub Cull(x As Single, y As Single, Z As Single)
  798. Dim Ax As Single
  799. Dim Ay As Single
  800. Dim Az As Single
  801. Dim nx As Single
  802. Dim ny As Single
  803. Dim nz As Single
  804.  
  805.     ' Compute a normal to the face.
  806.     NormalVector nx, ny, nz
  807.  
  808.     ' Compute a vector from the center of
  809.     ' projection to the face.
  810.     Ax = Points(1).coord(1) - x
  811.     Ay = Points(1).coord(2) - y
  812.     Az = Points(1).coord(3) - Z
  813.     
  814.     ' See if the vectors meet at an angle < 90.
  815.     IsCulled = (Ax * nx + Ay * ny + Az * nz > -0.0001)
  816. End Sub
  817.  
  818. ' ************************************************
  819. ' Read a polyline from a file using Input.
  820. ' Assume the "POLYGON" label has already been
  821. ' read.
  822. ' ************************************************
  823. Public Sub FileInput(filenum As Integer)
  824. Dim i As Integer
  825.  
  826.     Input #filenum, NumPts
  827.     
  828.     ' Allocate and read the points.
  829.     ReDim Points(1 To NumPts)
  830.     For i = 1 To NumPts
  831.         Input #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  832.         Points(i).coord(4) = 1#
  833.     Next i
  834. End Sub
  835.  
  836.  
  837.